import os
import pandas as pd
import numpy as ny

from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
from sklearn import metrics
from sklearn.tree import DecisionTreeClassifier


class MachineLearn(object):
    """机器学习类"""

    def __init__(self, sex, age, fare, alone):
        """初始化数据，准备数据
        params: 性别， 年龄， 费用， 是否独身
        """
        # 加载数据集
        path = os.path.abspath(os.path.dirname(__file__)) + os.sep
        file_path = path + "data" + os.sep + "titanic.csv"
        save_path = path + "data" + os.sep + "ml.csv"
        if not os.path.exists(save_path):
            data_train = pd.read_csv(file_path)
            # print(data_train)

            # todo 处理年龄空值问题
            data_train['Initial'] = 0  # 新增一列， 获取称呼
            data_train['Initial'] = data_train['Name'].str.extract('(\w+)\.')
            # print(data_train['Initial'].unique())
            """ 不同的称呼
            'Mr' 'Mrs' 'Miss' 'Master' 'Don' 'Rev' 'Dr' 'Mme' 'Ms' 'Major' 'Lady'
               'Sir' 'Mlle' 'Col' 'Capt' 'Countess' 'Jonkheer'
            # 称呼 再划分几类： 
                 Miss:   ms  ,Mme ,mlle
                 Mrs  : Lady , Countess
                 Mr  : Major , Capt, sir , Don , Dr
                 Other: Jonkheer, Col  , Rev
            """
            data_train['Initial'].replace(['Ms', 'Mme', 'Mlle'], ['Miss', 'Miss', 'Miss'], inplace=True)
            data_train['Initial'].replace(['Lady', 'Countess'], ['Mrs', 'Mrs'], inplace=True)
            data_train['Initial'].replace(['Major', 'Capt', 'Sir', 'Don', 'Dr'], ['Mr', 'Mr', 'Mr', 'Mr', 'Mr'],
                                          inplace=True)
            data_train['Initial'].replace(['Jonkheer', 'Col', 'Rev'], ['Other', 'Other', 'Other'], inplace=True)
            # 对不同类称呼的人 年龄求平均
            # print(data_train.groupby("Initial")["Age"].mean())
            """
            Master     4.574167
            Miss      21.860000
            Mr        32.739609
            Mrs       35.981818
            Other     45.888889
            """
            # 空值年龄填充
            data_train['Age_new'] = data_train['Age']  # 新生成一列， 复制原来的年龄
            data_train.loc[(data_train["Age"].isnull()) & (data_train["Initial"] == "Master"), "Age_new"] = 5
            data_train.loc[(data_train["Age"].isnull()) & (data_train["Initial"] == "Miss"), "Age_new"] = 22
            data_train.loc[(data_train["Age"].isnull()) & (data_train["Initial"] == "Mr"), "Age_new"] = 33
            data_train.loc[(data_train["Age"].isnull()) & (data_train["Initial"] == "Mrs"), "Age_new"] = 36
            data_train.loc[(data_train["Age"].isnull()) & (data_train["Initial"] == "Other"), "Age_new"] = 46
            # print(data_train['Age'],data_train["Age_new"])

            # todo 是否是小孩：年龄小于等于10岁  添加一个是否为小孩的列
            data_train["Child_new"] = 0  # 默认 不是小孩
            data_train.loc[data_train["Age_new"] <= 10, "Child_new"] = 1

            # todo 年龄离散化
            # print(data_train["Age_new"].describe())
            """
            min        0.420000
            25%       22.000000
            50%       30.000000
            75%       36.000000
            max       80.000000
            """
            data_train.loc[(data_train["Age_new"] >= 0.42) & (data_train["Age_new"] <= 22), "Age_new"] = 0
            data_train.loc[(data_train["Age_new"] > 22) & (data_train["Age_new"] <= 30), "Age_new"] = 1
            data_train.loc[(data_train["Age_new"] > 30) & (data_train["Age_new"] <= 36), "Age_new"] = 2
            data_train.loc[(data_train["Age_new"] > 36) & (data_train["Age_new"] <= 80), "Age_new"] = 3
            # print(data_train["Age_new"])

            # todo 费用离散化
            # print(data_train["Fare"].describe())
            """
            min        0.000000
            25%        7.910400
            50%       14.454200
            75%       31.000000
            max      512.329200
            """
            data_train["Fare_new"] = 0  # 新创建一列 ，用来保存 费用 的离散数据
            data_train.loc[(data_train["Fare"] >= 0) & (data_train["Fare"] < 7.910400), "Fare_new"] = 0
            data_train.loc[(data_train["Fare"] >= 7.910400) & (data_train["Fare"] < 14.454200), "Fare_new"] = 1
            data_train.loc[(data_train["Fare"] >= 14.454200) & (data_train["Fare"] < 31.000000), "Fare_new"] = 2
            data_train.loc[(data_train["Fare"] >= 31.000000) & (data_train["Fare"] <= 512.329200), "Fare_new"] = 3
            # print(data_train["Fare_new"])
            # todo性别编码化
            data_train["Sex_new"] = 0  # 0表示男性
            data_train.loc[data_train["Sex"] == "female", "Sex_new"] = 1
            # todo是否是独身
            data_train["Alone_new"] = 1  # 1表示独身
            data_train.loc[data_train["SibSp"] + data_train["Parch"] > 0, "Alone_new"] = 0  # 表示不是 独身

            # todo构造一个新的数据集 ： 抽取特征，特征工程
            train_tf = data_train.filter(regex="Survived|.*_new")  # 过滤列数据
            # print(train_tf.head())
            train_tf.to_csv(save_path, index=False)  # index=False表示不保存索引

        # 1. 构造数据
        data = pd.read_csv(save_path)
        x = data.iloc[:, 1:]
        y = data.iloc[:, 0]
        self.x = x
        self.y = y
        print(x.head())
        print(y.head())

        # 训练集与测试集切分
        self.x_train, self.x_test, self.y_train, self.y_test = \
            train_test_split(x, y, test_size=0.2, random_state=8)

        # todo 输入数据加工预处理
        # 性别预处理
        if sex == "male":
            self.sex = 0  # 男性
        else:
            self.sex = 1  # 女性

        # 是否为小孩预处理
        age = float(age)
        if age <= 10:
            self.child = 1  # 小于等于10岁 认为是小孩
        else:
            self.child = 0
        # 年龄预处理
        if age <= 22:
            self.age = 0
        elif age <= 30:
            self.age = 1
        elif age <= 36:
            self.age = 2
        else:
            self.age = 3
        # 是否为独身 预处理
        self.alone = int(alone)

        # 费用预处理
        """
        min        0.000000
        25%        7.910400
        50%       14.454200
        75%       31.000000
        max      512.329200
        """
        fare = float(fare)
        if fare < 7.910400:
            self.fare = 0
        elif fare < 14.454200:
            self.fare = 1
        elif fare < 31.000000:
            self.fare = 2
        else:
            self.fare = 3

        # 4个输入参数封装在一个列表中
        self.pred=[[self.age,self.child,self.fare,self.sex,self.alone]]

    def knn(self):
    	#todo：参数调优
    	#model = KNeighborsClassifier()
	    #hyper = {"n_neighbors":list(range(2,50))}
	    #model = GridSearchCV(estimator=model,param_grid=hyper,verbose=True)
	    #model.fit(self.x_train,self.y_train)
	    #print(model.best_estimator_) #n_neighbors=11

        # 2. 构建模型
        model = KNeighborsClassifier(n_neighbors=11)
        # 3.模型训练
        model.fit(self.x_train, self.y_train)
        # 4.模型测试
        pred_y = model.predict(self.x_test)
        # 5.模型评估
        acc = round(metrics.accuracy_score(self.y_test, pred_y), 2)
        # 6.模型应用
        des_pred = model.predict(self.pred)[0]
        if des_pred:
            des_pred = "-存活-"
        else:
            des_pred = "-死亡-"
        print(des_pred,acc)
        return des_pred, acc

    def decisionTree(self):
        """决策树模型预测"""
        # 导入模块from sklearn.tree import DecisionTreeClassifier
        # 2. 构建模型
        model = DecisionTreeClassifier(criterion="gini") # criterion 划分依据标准
        # 3.模型训练
        model.fit(self.x_train, self.y_train)
        # 4.模型测试
        pred_y = model.predict(self.x_test)
        # 5.模型评估
        acc = round(metrics.accuracy_score(self.y_test, pred_y), 2)
        # 6.模型应用
        des_pred = model.predict(self.pred)[0]
        if des_pred:
            des_pred = "-存活-"
        else:
            des_pred = "-死亡-"
        print(des_pred,acc)
        return des_pred, acc


if __name__ == '__main__':
    #  sex, age, fare, alone
    ml = MachineLearn("male","22","130","1")
    ml.knn()
    ml.decisionTree()
